from multiprocessing import Queue

from process import Process
from .detect import Detecter


class DetecterPool(Process):

    def __init__(self, config, stream_queue, error_queue):
        super().__init__()
        Detecter.init(config)
        self._alerter_queue = Queue()
        self._pusher_queue = Queue()
        if not config.multiprocess:
            self._add_process(
                config, 
                stream_queue, 
                self._alerter_queue, 
                self._pusher_queue, 
                Detecter.MODEL_NPU_CORE.CORE_AUTO,
                error_queue
            )
        else:
            model_npu_list = (
                Detecter.MODEL_NPU_CORE.CORE_0,
                Detecter.MODEL_NPU_CORE.CORE_1,
                Detecter.MODEL_NPU_CORE.CORE_2
            )
            for i in range(config.mutiprocess_worker_num):
                self._add_process(
                    config, 
                    stream_queue, 
                    self._alerter_queue, 
                    self._pusher_queue, 
                    model_npu_list[i % len(model_npu_list)],
                    error_queue
                )
        self._start()

    def _run(self, config, stream_queue, alerter_queue, pusher_queue, model_npu, error_queue):
        detecter = Detecter(config, model_npu)
        multiprocess = config.multiprocess
        proc_thresh = config.mutiprocess_worker_num * 2
        del config, model_npu

        # 1进程：平均检测 0.084s；fps **；平均闲置 0.030s
        # 2进程：平均检测 0.108s；fps 15；平均闲置 0.030s
        # 3进程：平均检测 0.115s；fps 19；平均闲置 0.040s
        # 4进程：平均检测 0.138s；fps 17；平均闲置 0.044s
        # 6进程：平均检测 0.157s；fps 13；平均闲置 0.101s
        # 9进程：平均检测 0.159s；fps 13；平均闲置 0.216s
        # 结论1：随着进程数增加，每个进程的检测开销增大
        # 结论2：fps在3进程时最高，小于该进程数导致来不及处理数据使帧率降低，高于该进程数导致平均检测时间较高使帧率降低
        # 结论3：随着进程数增加，每个进程的闲置时间增加，导致进程利用不充分，但整体所需内存增加
        try:
            while True:
                id, frame = stream_queue.get()
                if multiprocess and pusher_queue.qsize() >= proc_thresh and id % 2 == 0:
                    # 只是为了让OrderQueue取到的ID连续
                    alerter_queue.put((id, None, None))
                    if multiprocess:
                        pusher_queue.put((id, None))
                    continue
                results = detecter.detect(frame)
                alerter_queue.put((id, frame, results))
                # 多进程推理需要绘图
                if multiprocess:
                    pusher_queue.put((id, detecter.draw(frame, results)))
                # 单进程补帧，让pusher绘图
                else:
                    pusher_queue.put(results)
        except Exception as e:
            error_queue.put(f'推理异常：{str(e)}')
        except:
            pass

    @property
    def alerter_queue(self):
        return self._alerter_queue

    @property
    def pusher_queue(self):
        return self._pusher_queue
